﻿/**
 * CJMath
 *
 * @author		Allen Chou
 * @version		0.0.5 (last update: Aug 11 2008)
 * @link        http://cjcat.blogspot.com
 * @link		http://cjcat2266.deviantart.com
 */

 /*
 * Copyright 2008 (C) Allen Chou (cjcat2266@gmail.com)
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use,
 * copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the
 * Software is furnished to do so, subject to the following
 * conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
 * OTHER DEALINGS IN THE SOFTWARE.
 */

package idv.cjcat{
	import flash.errors.IllegalOperationError;

	public class CJMath {
		
		//mathematical shortcuts
		//------------------------------------------------------------------------------------------------
		
		public static function clamp(input:Number, lowerBound:Number, upperBound:Number):Number {
			if (lowerBound > upperBound) throw new IllegalOperationError("the lowerBound must be less than the upperBound.");
			if (input < lowerBound) return lowerBound;
			if (input > upperBound) return upperBound;
			return input;
		}
		
		public static function interpolate(x1:Number, y1:Number, x2:Number, y2:Number, x3:Number, usePercentage:Boolean = false):Number {
			if (x1 == x2) throw new IllegalOperationError("x1 must not equal to x2.");
			if (!usePercentage) return y1 - ((y1 - y2) * (x1 - x3) / (x1 - x2));
			return y1 - ((y1 - y2) * x3);
		}
		
		public static function linearLoop(x1:Number, y1:Number, x2:Number, y2:Number, x3:Number, usetPercentage:Boolean = false):Number {
			var remainder:Number = x3 % (x2 - x1);
			if (x2 < x1) remainder *= -1;
			return interpolate(x1, y1, x2, y2, x1 + remainder, usetPercentage);
		}
		
		public static function setPrecision(value:Number, digit:int, includeInteger:Boolean = false):Number {
			if (!includeInteger) {
				value *= Math.pow(10, digit);
				value = Math.round(value);
				value /= Math.pow(10, digit);
				return value;
			} else {
				var log:Number = Math.ceil(Math.log(value) / Math.log(10));
				value /= Math.pow(10, log);
				value *= Math.pow(10, digit)
				value  = Math.round(value);
				value /= Math.pow(10, digit);
				value *= Math.pow(10, log);
				return value;
			}
		}
		
		public static function between(value:Number, min:Number, max:Number, openMin:Boolean = false, openMax:Boolean = false):Boolean {
			if (min > max) throw new IllegalOperationError("min must be less than max.");
			if ((openMin?(value > min):(value >= min) && (openMax?(value < max):(value <= max)))) {
				return true;
			} else {
				return false;
			}
		}
		
		public static function sin(phase:Number, radius:Number = 1, offset:Number = 0):Number {
			return radius * Math.sin(phase) + offset;
		}
		
		public static function cos(phase:Number, radius:Number = 1, offset:Number = 0):Number {
			return radius * Math.cos(phase) + offset;
		}
		
		//end of mathematical shortcuts
		//------------------------------------------------------------------------------------------------
		
		
		//probability functions
		//------------------------------------------------------------------------------------------------
		
		public static function randomInt(max:uint):int {
			return Math.floor(Math.random() * (max + 1));
		}
		
		public static function pseudoGaussian(mean:Number, deviation:Number, iterations:int = 3):Number {
			if (iterations <= 0) return mean;
			var temp:Number = 0;
			for (var i:int = 1; i <= iterations; i++) {
				temp += (Math.random() - 0.5) * 2 * deviation;
			}
			temp /= iterations;
			temp += mean;
			return temp;
		}
		
		public static function uniformSample(mean:Number, deviation:Number, usePercent:Boolean = true):Number {
			if (usePercent) return mean + (Math.random() - 0.5) * deviation * 2 * mean;
			return mean + (Math.random() - 0.5) * deviation * 2;
		}
		
		//end of probability functions
		//------------------------------------------------------------------------------------------------
	}
}